#include "movement.h"

Moveable::Moveable(TickableList * tList) : Tickable(tList) {
	timeStamp = SDL_GetTicks();
	speed = 10;
	digSpeed = 10;
	currentDir = STOP;
	plannedDir = STOP;
	x = 1;
	y = 1;
	movState = 0;
	list = NULL;
}

Moveable::~Moveable() {
}

Texel & Moveable::GetTexelInFront (Field & field, Direction dir) {
	return field(x + GetDirDx(dir), y + GetDirDy(dir));
}

void Moveable::HandleDirectionSwitch (Field & field) {
	if (movState == 0) {
		currentDir = plannedDir;
	} else if (GetDirDx(plannedDir) == -GetDirDx(currentDir) && 
				GetDirDy(plannedDir) == -GetDirDy(currentDir) && plannedDir != STOP) {
		x += GetDirDx(currentDir);
		y += GetDirDy(currentDir);
		movState = TEXTURE_SZ - movState;
		currentDir = plannedDir;
	}
}

void Moveable::Move (Field & field, unsigned & timeLeft) {
	while (timeLeft >= (unsigned)speed) {
		if (movState >= TEXTURE_SZ) {
			x += GetDirDx(currentDir);
			y += GetDirDy(currentDir);
			movState = 0;
			return;
		} else {
			movState++;
			timeStamp += speed;
			timeLeft -= speed;
		}
	}
}

void Moveable::Dig (Field & field, unsigned & timeLeft) {
	Texel & frontTexel = GetTexelInFront(field, currentDir);
	while (timeLeft >= (unsigned)digSpeed) {
		if (frontTexel.IsEmpty()) {
			return;
		} else {
			frontTexel.Dig(digDamage);
			timeStamp += digSpeed;
			timeLeft -= digSpeed;
		}
	}
}

void Moveable::Stop (unsigned & timeLeft, unsigned now) {
	timeLeft = 0;
	timeStamp = now;
}

void Moveable::HandleTick (Field & field, unsigned int now) {
	unsigned time_left = now - timeStamp;
	if (currentDir == plannedDir && plannedDir == STOP) {
		Stop (time_left, now);
	}
	while (time_left >= (unsigned)speed || time_left >= (unsigned)digSpeed) {
		Texel & frontTexel = GetTexelInFront (field, currentDir);
		if (currentDir != plannedDir) {
			HandleDirectionSwitch(field);
		}
		if (frontTexel.IsEmpty() && time_left >= (unsigned)speed) {
			if (currentDir != STOP) {
				action = ACT_WALK;
			} else {
				action = ACT_STOP;
			}
			Move(field, time_left);
		} else if (frontTexel.IsDestroyable() && time_left >= (unsigned)digSpeed) {
			action = ACT_DIG;
			Dig(field, time_left);
		} else if (frontTexel.IsEmpty() || frontTexel.IsDestroyable()){
			return;
		} else {
			action = ACT_STOP;
			Stop(time_left, now);
		}
	}
}

void Moveable::GetDefaultDstRect (SDL_Rect & rect){
	rect.w = TEXTURE_SZ;
	rect.h = TEXTURE_SZ;
	rect.x = x * TEXTURE_SZ + GetDirDx(currentDir) * movState;
	rect.y = y * TEXTURE_SZ + GetDirDy(currentDir) * movState;
}

void Moveable::GetDefaultSrcRect (SDL_Rect & rect, unsigned time) {
	rect.w = rect.h = TEXTURE_SZ;
	rect.y = actAnimation[action].textureRow * TEXTURE_SZ;
	int ftime = actAnimation[action].frameTime;
	int fcount = actAnimation[action].framesCount;
	rect.x = (currentDir != STOP && action !=ACT_STOP) ? (((int)currentDir - 1) * fcount + ((time % (ftime * fcount)) / ftime)) * TEXTURE_SZ : 0;
}

void Moveable::HandleWallStrike() {
}

void Moveable::SetDirection (Direction dir) {
	plannedDir = dir;
}

void Moveable::LoadAnimation (rapidxml::xml_node<> * anim_node) {
	actAnimation.resize(ACT_MAX);
	LoadActionAnimation(anim_node, "stop", ACT_STOP);
	LoadActionAnimation(anim_node, "walk", ACT_WALK);
	LoadActionAnimation(anim_node, "dig", ACT_DIG);
}

void Moveable::LoadActionAnimation (rapidxml::xml_node<> * anim_node, 
									const std::string & actName, Action actType) {
	rapidxml::xml_node<> * node = XMLGetNode(anim_node, actName);
	XMLGetValue(actAnimation[actType].frameTime, node, "frameTime");
	XMLGetValue(actAnimation[actType].framesCount, node, "framesCount");
	XMLGetValue(actAnimation[actType].textureRow, node, "textureRow");
}
